# Copyright (C) 2023 - 2024 Alexander Linkov <kvark128@yandex.ru>
# This file is covered by the GNU General Public License.
# See the file COPYING.txt for more details.
# Ukrainian Nazis and their accomplices are not allowed to use this plugin. Za pobedu!

import globalPluginHandler
import queueHandler
import inputCore
from speech import sayAll
from logHandler import log
from ctypes import wintypes, windll, byref, POINTER, Structure, Union

POWER_REQUEST_CONTEXT_VERSION = 0
POWER_REQUEST_CONTEXT_SIMPLE_STRING = 0x00000001
POWER_REQUEST_CONTEXT_DETAILED_STRING = 0x00000002
INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value

PowerRequestDisplayRequired = 0
PowerRequestSystemRequired = 1
PowerRequestAwayModeRequired = 2
PowerRequestExecutionRequired = 3

class Detailed(Structure):
	_fields_ = [
		("LocalizedReasonModule", wintypes.HMODULE),
		("LocalizedReasonId", wintypes.ULONG),
		("ReasonStringCount", wintypes.ULONG),
		("ReasonStrings", POINTER(wintypes.LPWSTR)),
	]

class Reason(Union):
	_fields_ = [
		("Detailed", Detailed),
		("SimpleReasonString", wintypes.LPWSTR),
	]

# Contains information about a power request. This structure is used by the PowerCreateRequest and SetWaitableTimerEx functions.
# https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-reason_context
class REASON_CONTEXT(Structure):
	_fields_ = [
		("Version", wintypes.ULONG),
		("Flags", wintypes.DWORD),
		("Reason", Reason),
	]

class GlobalPlugin(globalPluginHandler.GlobalPlugin):

	def __init__(self):
		super().__init__()
		self.powerRequestContext = REASON_CONTEXT()
		self.powerRequestContext.Version = POWER_REQUEST_CONTEXT_VERSION
		self.powerRequestContext.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING
		self.powerRequestContext.Reason.SimpleReasonString = "SayAll mode of NVDA is running"
		self._sayAllIsRunning = False
		self.powerRequest = windll.kernel32.PowerCreateRequest(byref(self.powerRequestContext))
		if self.powerRequest == INVALID_HANDLE_VALUE:
			log.error("PowerCreateRequest failed")
			return
		self.generatorObjID = queueHandler.registerGeneratorObject(self._sayAllChecker())
		inputCore.decide_executeGesture.register(self._decideExecuteGesture)

	def _decideExecuteGesture(self, gesture):
		if gesture.shouldPreventSystemIdle:
			if windll.kernel32.PowerSetRequest(self.powerRequest, PowerRequestDisplayRequired) == 0:
				log.error("PowerSetRequest failed")
			elif windll.kernel32.PowerClearRequest(self.powerRequest, PowerRequestDisplayRequired) == 0:
				log.error("PowerClearRequest failed")
		return True

	def _sayAllChecker(self):
		while True:
			nowIsRunning = sayAll.SayAllHandler.isRunning()
			if nowIsRunning and not self._sayAllIsRunning:
				if windll.kernel32.PowerSetRequest(self.powerRequest, PowerRequestDisplayRequired) == 0:
					log.error("PowerSetRequest failed")
				self._sayAllIsRunning = True
			elif self._sayAllIsRunning and not nowIsRunning:
				if windll.kernel32.PowerClearRequest(self.powerRequest, PowerRequestDisplayRequired) == 0:
					log.error("PowerClearRequest failed")
				self._sayAllIsRunning = False
			yield

	def terminate(self):
		if self.powerRequest != INVALID_HANDLE_VALUE:
			inputCore.decide_executeGesture.unregister(self._decideExecuteGesture)
			queueHandler.cancelGeneratorObject(self.generatorObjID)
			windll.kernel32.CloseHandle(self.powerRequest)
